Skip to content

fix(solid-form): generate an SSR-safe default formId - #2263

Open
harshit-d3v wants to merge 2 commits into
TanStack:mainfrom
harshit-d3v:fix/solid-form-ssr-safe-form-id
Open

fix(solid-form): generate an SSR-safe default formId#2263
harshit-d3v wants to merge 2 commits into
TanStack:mainfrom
harshit-d3v:fix/solid-form-ssr-safe-form-id

Conversation

@harshit-d3v

@harshit-d3v harshit-d3v commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Changes

When no formId is configured, createForm provides no fallback, so FormApi generates a random uuid() — seeded from Math.random(), and therefore different between the server render and the client render. Binding that generated id produces a hydration mismatch under SolidStart:

const form = createForm(() => ({ defaultValues: { firstName: '' } }))

<form id={form.formId}>   {/* server: "d8efe189-…"   client: "4b1c07a2-…" */}

An explicitly provided formId was already forwarded and is unchanged by this PR.

This is the same bug as #2254, which #2259 fixed for Vue. Solid is the remaining adapter with an SSR story that hadn't had the treatment the others already have:

Solid's counterpart is createUniqueId(), which derives the id from the hydration context when one is present, so both renders agree. packages/solid-form/src/createForm.tsx now uses it for the default.

Test plan

packages/solid-form/tests/createFormId.test.tsx covers both branches — an explicit formId is returned unchanged, and the default comes from Solid's id sequence rather than a random uuid. Before the change the second test fails with:

expected 'd8efe189-c90f-4667-ac96-e9685217a6a4' to match /^cl-\d+$/

The first test passes both before and after, which is the evidence that explicit ids were never affected.

Full @tanstack/solid-form suite passes (46 tests, 5 files), tsc --noEmit is clean, and eslint ./src ./tests reports no new problems.

One thing worth flagging

I wasn't able to assert the server/client round-trip directly the way vue-form/tests/useFormId.test.tsx does. Under solid-form's current vitest config, solid-js/web resolves to the client build — isServer is false and renderToString() returns undefined — so an SSR render can't be exercised without a second vitest project configured with server conditions and solid({ ssr: true }).

Rather than grow this PR into a test-infrastructure change, the test pins the default to Solid's id sequence, which is the property that makes hydration agree. Happy to add the SSR project setup here or in a follow-up if you'd prefer the stronger assertion — just say which.

Summary by CodeRabbit

  • Bug Fixes

    • Improved server-side rendering and hydration reliability for Solid forms with stable default form IDs.
    • Explicitly configured form IDs continue to work unchanged.
  • Tests

    • Added coverage for custom form IDs and hydration-safe default IDs.

`createForm` never passed a `formId` to `FormApi`, so it fell back to
`uuid()`, which is seeded from `Math.random()` and therefore differs
between the server render and the client render. Binding it
(`<form id={form.formId}>`) produced a hydration mismatch under
SolidStart.

Use Solid's `createUniqueId()` for the default instead, which is what
the other adapters already do:

- react-form/src/useFormId.ts   — React.useId, falling back to useUUID on React 17
- preact-form/src/useFormId.ts  — useId from preact/hooks
- vue-form/src/useFormId.ts     — Vue's useId, added in TanStack#2259

An explicitly provided `formId` is still preserved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

createForm now uses Solid’s createUniqueId for SSR-safe default form IDs. Explicit formId values remain unchanged. Tests cover both ID paths, and a patch changeset documents the update.

Changes

Solid form ID generation

Layer / File(s) Summary
Generate and pass fallback form IDs
packages/solid-form/src/createForm.tsx
createForm generates a fallback ID with createUniqueId when no formId is configured and passes the selected ID to FormApi.
Validate form IDs and record the patch release
packages/solid-form/tests/createFormId.test.tsx, .changeset/great-pugs-shave.md
Tests verify explicit IDs and the default cl-<n> format. The changeset documents the SSR-safe ID behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • TanStack/form#2259: Both PRs add SSR-safe default formId generation for framework-specific form initialization.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: generating an SSR-safe default formId for Solid Form.
Description check ✅ Passed The description clearly explains the change, motivation, test plan, and SSR test limitation, but omits the template's Checklist and Release Impact sections.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/great-pugs-shave.md:
- Line 5: Update the changeset description to state that createForm lacked an
SSR-safe fallback formId when options.formId was not provided, while
acknowledging explicit formId values were already forwarded. Capitalize React,
Preact, and Vue.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a9093e8e-c3b3-46d7-9424-841669e144dc

📥 Commits

Reviewing files that changed from the base of the PR and between 028fcdd and 3b92536.

📒 Files selected for processing (3)
  • .changeset/great-pugs-shave.md
  • packages/solid-form/src/createForm.tsx
  • packages/solid-form/tests/createFormId.test.tsx

Comment thread .changeset/great-pugs-shave.md Outdated
An explicitly provided `formId` was already forwarded to `FormApi`; only
the fallback was missing. Say that, and capitalize the framework names.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@harshit-d3v

Copy link
Copy Markdown
Contributor Author

Good catch — corrected in c3d1e40. Explicit formId values were always forwarded; only the fallback was missing, and the changeset now says that. Framework names capitalized in both the changeset and the source comment.

Worth noting the test file already documented this: uses the provided formId when one is given passes both before and after the fix, so the explicit path was never affected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant